package org.asiainfo.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import lombok.RequiredArgsConstructor;
import org.asiainfo.common.mybatis.stream.core.page.PageQuery;
import org.asiainfo.common.mybatis.stream.core.page.TableDataInfo;
import org.asiainfo.common.core.constant.CacheNames;
import org.asiainfo.common.core.exception.ServiceException;
import org.asiainfo.common.core.utils.MapstructUtils;
import org.asiainfo.common.core.utils.StringUtils;
import org.asiainfo.common.redis.utils.CacheUtils;
import org.asiainfo.system.domain.SysDictData;
import org.asiainfo.system.domain.bo.SysDictTypeBo;
import org.asiainfo.system.domain.vo.SysDictDataVo;
import org.asiainfo.system.domain.vo.SysDictTypeVo;
import org.asiainfo.system.mapper.SysDictDataMapper;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.asiainfo.system.service.SysDictTypeService;
import org.asiainfo.system.domain.SysDictType;
import org.asiainfo.system.mapper.SysDictTypeMapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 字典类型表 服务层实现。
 *
 * @author dotor-ww
 */
@Service
@RequiredArgsConstructor
public class SysDictTypeServiceImpl extends ServiceImpl<SysDictTypeMapper, SysDictType> implements SysDictTypeService {

    private final SysDictDataMapper sysDictDataMapper;

    /**
     * 查询所有字典类型表
     *
     * @param dictTypeBo 字典类型
     * @param pageQuery  分页信息
     * @return 字典类型
     */
    @Override
    public TableDataInfo<SysDictTypeVo> selectPageDictTypeList(SysDictTypeBo dictTypeBo, PageQuery pageQuery) {
        Map<String, Object> params = dictTypeBo.getParams();
        QueryWrapper query = query()
            .like(SysDictType::getDictName, dictTypeBo.getDictName(), StringUtils.isNotBlank(dictTypeBo.getDictName()))
            .like(SysDictType::getDictType, dictTypeBo.getDictType(), StringUtils.isNotBlank(dictTypeBo.getDictType()))
            .between(SysDictType::getCreateTime, params.get("beginTime"), params.get("endTime"),
                ObjectUtil.isNotNull(params.get("beginTime")) && ObjectUtil.isNotNull(params.get("endTime")));
        pageQuery.buildOrder(query);
        Page<SysDictTypeVo> page = pageAs(pageQuery.buildPage(), query, SysDictTypeVo.class);
        return TableDataInfo.build(page);
    }

    /**
     * 根据字典类型ID查询信息
     *
     * @param dictId 字典类型ID
     * @return 字典类型
     */
    @Override
    public SysDictTypeVo selectDictTypeById(Long dictId) {
        return getOneAs(query().eq(SysDictType::getDictId, dictId), SysDictTypeVo.class);
    }

    /**
     * 新增保存字典类型信息
     *
     * @param sysDictTypeBo 字典类型信息
     * @return 结果
     */
    @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#sysDictTypeBo.dictType")
    @Override
    public List<SysDictDataVo> insertDictType(SysDictTypeBo sysDictTypeBo) {
        SysDictType dict = MapstructUtils.convert(sysDictTypeBo, SysDictType.class);
        if (save(dict)) {
            return new ArrayList<>();
        }
        throw new ServiceException("插入操作失败");
    }

    /**
     * 校验字典类型称是否唯一
     *
     * @param dictTypeBo 字典类型
     * @return 结果
     */
    @Override
    public boolean checkDictTypeUnique(SysDictTypeBo dictTypeBo) {
        return exists(query()
            .eq(SysDictType::getDictType, dictTypeBo.getDictType())
            .ne(SysDictType::getDictId, dictTypeBo.getDictId(), ObjectUtil.isNotNull(dictTypeBo.getDictId())));
    }

    /**
     * 修改保存字典类型信息
     *
     * @param sysDictTypeBo 字典类型信息
     * @return 结果
     */
    @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#sysDictTypeBo.dictType")
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<SysDictDataVo> updateDictType(SysDictTypeBo sysDictTypeBo) {
        SysDictType newSysDictType = MapstructUtils.convert(sysDictTypeBo, SysDictType.class);
        if (ObjectUtil.isNull(newSysDictType)) {
            throw new ServiceException("字典类型不能为空");
        }
        SysDictType oldSysDictType = getById(newSysDictType.getDictId());

        UpdateChain.of(SysDictData.class)
            .from(SysDictData.class)
            .set(SysDictData::getDictType, newSysDictType.getDictType())
            .where(SysDictData::getDictType)
            .eq(oldSysDictType)
            .update();

        if (updateById(newSysDictType)) {
            CacheUtils.evict(CacheNames.SYS_DICT, oldSysDictType.getDictType());
            return sysDictDataMapper.selectListByQueryAs(query()
                .and(SysDictData::getDictType)
                .eq(newSysDictType.getDictType())
                .orderBy(SysDictData::getCreateTime, false), SysDictDataVo.class);
        }
        throw new ServiceException("操作失败");
    }

    /**
     * 根据字典类型查询字典数据
     *
     * @param dictType 字典类型
     * @return 字典数据集合信息
     */
    @Cacheable(cacheNames = CacheNames.SYS_DICT, key = "#dictType")
    @Override
    public List<SysDictDataVo> selectDictDataByType(String dictType) {
        QueryWrapper queryWrapper = query().and(SysDictData::getDictType).eq(dictType).orderBy(SysDictData::getCreateTime, false);
        return sysDictDataMapper.selectListByQueryAs(queryWrapper, SysDictDataVo.class);
    }

    /**
     * 批量删除字典类型信息
     *
     * @param dictIds 需要删除的字典ID
     */
    @Override
    public void deleteDictTypeByIds(Long[] dictIds) {
        for (Long dictId : dictIds) {
            SysDictType dictType = getById(dictId);
            long count = sysDictDataMapper.selectCountByQuery(query().eq(SysDictData::getDictType, dictType.getDictType()));
            if (count > 0) {
                throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName()));
            }
            CacheUtils.evict(CacheNames.SYS_DICT, dictType.getDictType());
        }
        removeByIds(Arrays.asList(dictIds));
    }

    /**
     * 重置字典缓存数据
     */
    @Override
    public void resetDictCache() {
        CacheUtils.clear(CacheNames.SYS_DICT);
    }

    /**
     * 根据所有字典类型
     *
     * @return 字典类型集合信息
     */
    @Override
    public List<SysDictTypeVo> selectDictTypeAll() {
        return listAs(query(), SysDictTypeVo.class);
    }
}
